package com.linkhub.oms.component.redis.config;

import com.google.common.collect.Lists;
import com.linkhub.oms.component.redis.locker.DistributedLocker;
import com.linkhub.oms.component.redis.locker.impl.RedissonDistributedLocker;
import org.apache.commons.lang3.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;
import org.redisson.config.SentinelServersConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;

/**
 * @Description: RedissonConfig
 * @Author: echo
 * @Date: 2024/3/3 11:29
 * @Version: 1.0
 */
@Configuration
public class RedissonConfig {

    /**
     * 连接redis服务端的方式
     */
    private enum ConnectType {
        /** 单机版 */
        SINGLE,
        /** 哨兵版 */
        SENTINEL,
        /** 集群版 */
        CLUSTER
    }

    /** redis地址前缀 */
    public static final String REDIS_ADDRESS_PREFIX = "redis://";
    private static final int SUBSCRIPTIONS_PER_CONNECTION = 200;

    @Resource
    private RedisProperties redisProperties;

    @Bean
    public RedissonClient redissonClient() {
        ConnectType connectType = this.getConnectType();
        return Redisson.create(this.getConfig(connectType));
    }

    @Bean
    @ConditionalOnBean(RedissonClient.class)
    public DistributedLocker distributedLocker(RedissonClient redissonClient) {
        return new RedissonDistributedLocker(redissonClient);
    }


    /**
     * 获取redis连接配置
     */
    private Config getConfig(ConnectType connectType) {
        Config config = new Config();
        switch (connectType) {
            case SINGLE:
                config = this.buildSingleServerConfig();
                break;
            case SENTINEL:
                config = this.buildSentinelServersConfig();
                break;
            case CLUSTER:
                config = this.buildClusterServersConfig();
                break;
            default:
                break;
        }
        return config;
    }

    /**
     * 单机配置
     */
    private Config buildSingleServerConfig() {
        Config config = new Config();

        String redisUrl = String.format("%s%s:%s", REDIS_ADDRESS_PREFIX, redisProperties.getHost(),
                redisProperties.getPort());

        config.useSingleServer()
                .setAddress(redisUrl)
                .setDatabase(redisProperties.getDatabase())
                .setPassword(StringUtils.stripToNull(redisProperties.getPassword()))
                .setConnectionMinimumIdleSize(redisProperties.getJedis().getPool().getMinIdle())
                .setConnectionPoolSize(redisProperties.getJedis().getPool().getMaxActive())
                .setSubscriptionsPerConnection(SUBSCRIPTIONS_PER_CONNECTION);

        return config;
    }

    /**
     * 哨兵配置
     */
    private Config buildSentinelServersConfig() {
        Config config = new Config();

        List<String> nodes = redisProperties.getSentinel().getNodes();
        String[] nodeArr = this.convertAddress(nodes);

        SentinelServersConfig serversConfig = config.useSentinelServers();
        serversConfig.setMasterName(redisProperties.getSentinel().getMaster());
        serversConfig.addSentinelAddress(nodeArr);
        serversConfig.setDatabase(redisProperties.getDatabase());
        serversConfig.setPassword(redisProperties.getPassword());
        serversConfig.setSubscriptionsPerConnection(SUBSCRIPTIONS_PER_CONNECTION);

        return config;
    }

    /**
     * 集群配置
     */
    private Config buildClusterServersConfig() {
        Config config = new Config();
        List<String> nodes = redisProperties.getCluster().getNodes();
        String[] nodeArr = this.convertAddress(nodes);

        ClusterServersConfig serversConfig = config.useClusterServers();
        serversConfig.addNodeAddress(nodeArr);
        serversConfig.setPassword(redisProperties.getPassword());
        serversConfig.setSubscriptionsPerConnection(SUBSCRIPTIONS_PER_CONNECTION);

        return config;
    }

    /**
     * 获取连接方式
     */
    private ConnectType getConnectType() {
        if (Objects.nonNull(redisProperties.getCluster())) {
            return ConnectType.CLUSTER;
        }

        if (Objects.nonNull(redisProperties.getSentinel())) {
            return ConnectType.SENTINEL;
        }

        return ConnectType.SINGLE;
    }

    /**
     * 转换redis地址
     */
    private String[] convertAddress(List<String> nodes) {
        List<String> resultList = Lists.newArrayList();
        for (String node : nodes) {
            resultList.add((node.startsWith(REDIS_ADDRESS_PREFIX) ? StringUtils.EMPTY : REDIS_ADDRESS_PREFIX) + node);
        }

        return resultList.toArray(new String[nodes.size()]);
    }
}
